using System;
using System.IO;
using System.Text;
using Toast.Core;

namespace Toast.Filters
{
    public class ContentInjectionFilter : Stream
    {
        readonly InjectAt _injectAt;
        readonly PositionalInjectionDictionary _pic;
        readonly Stream _responseStream;
        readonly StringBuilder _responseText = new StringBuilder();

        #region Properties

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override long Length
        {
            get { return _responseStream.Length; }
        }

        public override long Position
        {
            get { return _responseStream.Position; }
            set { throw new InvalidOperationException("Cannot set the position of a filter stream"); }
        }

        public override bool CanRead
        {
            get { return false; }
        }

        #endregion

        internal ContentInjectionFilter(Stream original, PositionalInjectionDictionary pic)
        {
            _responseStream = original;
            _pic = pic;
        }

        void FlushContents(string contents, string anchor, string s)
        {
            contents = string.IsNullOrEmpty(anchor) ? contents + s : contents.Replace(anchor, s + anchor);

            var bytes = Encoding.UTF8.GetBytes(contents);
            _responseStream.Write(bytes, 0, bytes.Length);
        }

        public override void Close()
        {
            _responseStream.Close();
        }

        public override void Flush()
        {
        }

        public override void SetLength(long length)
        {
            _responseStream.SetLength(length);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            var str = Encoding.UTF8.GetString(buffer, offset, count);

            _responseText.Append(str);

            var contents = _responseText.ToString();

            //TODO: Better logic required here.
            if (contents.Contains("</head>") && _pic.ContainsKey(InjectAt.HeadBottom))
                FlushContents(contents, "</head>", _pic[InjectAt.HeadBottom]);
            else if (contents.Contains("</body>") && _pic.ContainsKey(InjectAt.BodyBottom))
                FlushContents(contents, "</body>", _pic[InjectAt.BodyBottom]);
            else if (_pic.ContainsKey(InjectAt.Inline))
                FlushContents(contents, "", _pic[InjectAt.Inline]);
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            throw new InvalidOperationException("Cannot Seek");
        }

        public override long Seek(long offset, SeekOrigin direction)
        {
            throw new InvalidOperationException("Cannot Seek");
        }
    }
}